/*
 * Created on Feb 6, 2005
 * Created by dfhuynh
 */
package edu.mit.simile;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.URL;
import java.net.URLConnection;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

import org.apache.log4j.Logger;

import com.hp.hpl.jena.datatypes.xsd.XSDDatatype;
import com.hp.hpl.jena.datatypes.xsd.XSDDateTime;
import com.hp.hpl.jena.db.IDBConnection;
import com.hp.hpl.jena.rdf.model.Model;

/**
 * @author dfhuynh
 */
public class SimileUtilities {
	final static private Logger s_logger = 
		Logger.getLogger(SimileUtilities.class);
	
	static public String fileToModelLang(File file) {
		return filenameToLang(file.getName());
	}

	static public String urlToModelLang(URL url, String contentType) {
		return urlToModelLang(url.getPath(), contentType);
	}
	
	static public String urlToModelLang(String url, String contentType) {
		String lang = null;
		
		if (contentType != null) {
			lang = contentTypeToLang(contentType);
		}
		if (lang == null) {
			lang = filenameToLang(url);
		}
		
		return lang;
	}

	static public String contentTypeToLang(String contentType) {
		if ("application/rss+xml".equals(contentType) ||
			"application/atom+xml".equals(contentType)) {
		
			return "RSS";
		} else if ("application/rdf+xml".equals(contentType) ||
			"text/xml".equals(contentType)) {
			
			return "RDF/XML";
		} else if ("application/n3".equals(contentType)) {
			return "N3";
		} else {
			return null;
		}
	}
	
	static public String filenameToLang(String filename) {
		String contentType = 
			URLConnection.guessContentTypeFromName(filename);
		String lang = null;
		
		if (contentType != null) {
			lang = contentTypeToLang(contentType);
		}
		
		if (lang == null) {
			if (filename.endsWith(".n3")) {
				lang = "N3";
			} else if (filename.endsWith(".xml") && filename.indexOf("rss") >= 0) {
				lang = "RSS";
			} else if (
				filename.endsWith(".rdf") || 
				filename.endsWith(".xml") || 
				filename.endsWith(".owl")
			) {
				lang = "RDF/XML";
			}
		}
		
		return lang;
	}
	
	static public String uriToFilename(String uri) {
		return uri.replace(':', '_').replace('/', '_');
	}
	
	static public void loadDataFromDir(File dir, Model model, boolean forgiving) throws IOException {
		if (!dir.exists()) {
			throw new FileNotFoundException("Cannot load data from " + dir.getAbsolutePath());
		}
		
		File[] files = dir.listFiles();
		
		for (int i = 0; i < files.length; i++) {
			File file = files[i];
			
			if (!file.isHidden()) {
				if (file.isDirectory()) {
					loadDataFromDir(file, model, forgiving);
				} else {
					if (forgiving) {
						try {
							loadDataFromFile(file, model);
						} catch (IOException e) {
							s_logger.warn(
								"Failed to load data from " + file.getCanonicalPath(),
								e
							);
						}
					} else {
						loadDataFromFile(file, model);
					}
				}
			}
		}
	}
	
	static public void loadDataFromFile(File file, Model model) throws IOException {
		String lang = SimileUtilities.fileToModelLang(file);
		if (lang != null) {
			FileInputStream fis = new FileInputStream(file);
			try {
				String url = file.toURL().toExternalForm();
				
				try {
					model.read(fis, url, lang);
				} catch (Exception e) {
					throw new ModelReadFromFileException(
						"Failed to read data from file " + file.getAbsolutePath(),
						e
					);
				}
				
				s_logger.info("Read file " + file.getCanonicalPath());
			} finally {
				fis.close();
			}
		}
	}

	static public Date parseDate(String s) {
		Date d = null;
		
		// HACK
		if (s.endsWith("Z")) {
			try {
				d = new SimpleDateFormat("yyyy-MM-dd'T'H:m:s.S'Z'").parse(s);
			} catch (ParseException e) {
			}
		} else {
			try {
				d = ((XSDDateTime) XSDDatatype.XSDdateTime.parse(s)).asCalendar().getTime();
			} catch (Exception e) {
			}
			
			if (d == null) {
				try {
					d = ((XSDDateTime) XSDDatatype.XSDdate.parse(s)).asCalendar().getTime();
				} catch (Exception e) {
				}
			}
		}

		return d;
	}
	
	static public String unparseDate(Date d) {
		//return d != null ? XSDDatatype.XSDdateTime.unparse(d) : null;
		
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ");
		String s = sdf.format(new Date());
		int l = s.length() - 2;
		
		return s.substring(0, l) + ":" + s.substring(l);
	}
	
	static public String reformatDate(String s) {
		Date d = parseDate(s);
		if (d != null) {
			return formatDate(d);
		} else {
			return s;
		}
	}

	static public String formatDate(Date d) {
		return d == null ? null : DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG).format(d);
	}
	
	static public String abbreviateURI(String uri) {
		int index = uri.lastIndexOf('#') + 1;
		if (index < 1) {
			index = uri.lastIndexOf('/') + 1;
		}
		if (index == uri.length()) {
			return uri;
		} else {
			return uri.substring(index);
		}
	}
	
	static public String escape(String s, char toEscape, char escaping, char escaped) {
		StringBuffer sb = new StringBuffer();
		char[] chars = s.toCharArray();
		
		for (int i = 0; i < chars.length; i++) {
			char c = chars[i];
			if (c == escaping) {
				sb.append(c).append(c);
			} else if (c == toEscape) {
				sb.append(escaping).append(escaped);
			} else {
				sb.append(c);
			}
		}
		return sb.toString();
	}
	
	static public String unescape(String s, char toEscape, char escaping, char escaped) {
		StringBuffer sb = new StringBuffer();
		char[] chars = s.toCharArray();
		
		for (int i = 0; i < chars.length; i++) {
			char c = chars[i];
			if (c == escaping && i < chars.length + 1) {
				char c2 = chars[i+1];
				if (c2 == escaping) {
					sb.append(escaping);
					i++;
				} else if (c2 == escaped) {
					sb.append(toEscape);
					i++;
				} else {
					sb.append(c);
				}
			} else {
				sb.append(c);
			}
		}
		return sb.toString();
	}

}

class ModelReadFromFileException extends IOException {
	ModelReadFromFileException(String s, Throwable e) {
		super(s);
		initCause(e);
	}
}